﻿
using Newtonsoft.Json.Serialization;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection; 
namespace AppSocketModel
{
    /// <summary>
    /// 向Swagger添加枚举值说明
    /// </summary>
    public class EnumDocumentFilter : IDocumentFilter
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="swaggerDoc"></param>
        /// <param name="context"></param> 
        public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
        { 
            Dictionary<string, Type> dict = GetAllEnum();
            // 向结果模型添加枚举描述 
            foreach (var item in swaggerDoc.Definitions)
            {
                var schema = item.Value;
                foreach (var propertyDictionaryItem in schema.Properties)
                {
                    var property = propertyDictionaryItem.Value;
                    var propertyEnums = property.Enum;
                    var typeName = propertyDictionaryItem.Key;

                    Type itemType = null;
                    if (propertyEnums != null && propertyEnums.Count > 0)
                    { 
                        string name = SnakeCaseToCamelCase(typeName);
                        if (dict.ContainsKey(name))
                        {
                            itemType = dict[name];
                        }
                        else
                        {
                            itemType = null;
                            continue;
                        }
                        List<string> list = new List<string>();
                        foreach (var aaa in propertyEnums)
                        {
                            list.Add(aaa.ToString());
                        }
                        property.Description += DescribeEnum(itemType,list);
                    }
                }

            }
        }
        /// <summary>
        /// 字符串蛇形转驼峰
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string SnakeCaseToCamelCase(string str)
        {
            var splits = str.Split('_');
            var result = splits.Select(s =>
            {
                if (s.Length > 0)
                    return s.Substring(0, 1).ToUpper() + s.Substring(1);
                else
                    return "";
            }).ToArray();
            return string.Join("", result);
        }
        private static Dictionary<string, Type> GetAllEnum()
        {
            Assembly ass = Assembly.Load("AppSocketModel");
            Type[] types = ass.GetTypes();
            Dictionary<string, Type> dict = new Dictionary<string, Type>();

            foreach (Type item in types)
            {
                if (item.IsEnum)
                {
                    dict.Add(item.Name, item);
                }
            }
            return dict;
        }

        private static string DescribeEnum(Type type, List<string> enums)
        {
            var enumDescriptions = new List<string>();
            foreach (var item in enums)
            {
                if (type == null) continue;
                var value = Enum.Parse(type, item);
                var desc = GetDescription(type, value);

                if (string.IsNullOrEmpty(desc))
                    enumDescriptions.Add($"{item}:{Enum.GetName(type, value)}; ");
                else
                    enumDescriptions.Add($"{item}:{Enum.GetName(type, value)},{desc}; ");

            }
            return $"<br/>{Environment.NewLine}{string.Join("<br/>" + Environment.NewLine, enumDescriptions)}<br/>";
        }

        private static string GetDescription(Type t, object value)
        {
            foreach (MemberInfo mInfo in t.GetMembers())
            {
                if (mInfo.Name == t.GetEnumName(value))
                {
                    foreach (Attribute attr in Attribute.GetCustomAttributes(mInfo))
                    {
                        if (attr.GetType() == typeof(DescriptionAttribute))
                        {
                            return ((DescriptionAttribute)attr).Description;
                        }
                    }
                }
            }
            return string.Empty;
        }
    }
}
